
#------------------------------------------------------------------------------
# Makefile to generate and run my personal blog
#
# It takes care of properly generating all files whitin the './posts' and the
# './pages' directory, with the './parts' directory contaning the dependencies
# (files which are part of other files).
#
# TODO:
# 	- Condenes 'template_post_with_deps' and 'template_no_deps' into a single
# 	  template
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# Static variables
#------------------------------------------------------------------------------

# Default domain and  port to be used to generate the site and to run the
# server. To use others, specify them via the command line
DOMAIN := https://localhost
PORT := 3000

.PHONY: build stylesheet cert key run clean

build := build
mkpage :=resources/mkpage.pl
macros :=resources/macros.m4
server := resources/server/server.js
stylesheet := resources/site/stylesheet.css
cert := resources/site/certificate.pem
key := resources/site/private-key.pem

stylesheet_target := build/stylesheet.css
cert_target := build/certificate.pem
key_target := build/private-key.pem

server_flags := -c $(cert_target) -k $(key_target)
mkpage_flags := -D '$(date)' -d $(DOMAIN)

ifneq ($(PORT),)
	server_flags += -p $(PORT)
	mkpage_flags += -p $(PORT) 
endif


#------------------------------------------------------------------------------
# Generated variables
#------------------------------------------------------------------------------

# Get the basename of a file without the intermediary suffix
# $1: File
# $2: Sufix to be removed
prepare_file = $(notdir $(subst $(2),,$(1)))

# Return the date a file was last modified
# $1: File
last_modified_date = $(shell date -r $(1) "+%B %d, %Y")

# Get all pages and posts
pages != find ./pages -name '*.page.html'
posts != find . -wholename './parts' -prune -o -name '*.post.html' -print

# Remove the intermediary suffixes from the files, leaving only the '.html'
posts_target := $(foreach post,$(posts),$(call prepare_file,$(post),.post))
pages_target := $(foreach page,$(pages),$(call prepare_file,$(page),.page))

# Posts and their dependencies for recipe generation
posts_with_deps != resources/post_deps.bash -d ./posts
posts_without_deps != resources/post_deps.bash ./posts
deps := $(foreach post,$(posts_with_deps),\
			$(wordlist 2,$(words $(subst :, ,$(post))),$(subst :, ,$(post))))

# Fetch each subdirectory from './posts' to populate M4PATH
# This allows the 'include' macro to work properly
export M4PATH := $(shell find ./parts -type d -exec printf {}: \;)

#------------------------------------------------------------------------------
# Templates for automatic recipe generation
#
# Notes:
# 	For Whatever reason, the target argument $(1) for 'template_with_deps' and
# 	'template_post_with_deps' acquired a leading space inside the recipe. As a
# 	workaround, trim it before using.
#------------------------------------------------------------------------------

# Function for recipe generation for files without dependencies
# $1: file list of targets
# $2: Suffix to be removed of targets
define gen_recipes_no_deps
$(foreach f,$(1),\
	$(eval $(call template_no_deps,\
		$(call prepare_file,$(f),.$(2)),$(f))))
endef

define template_no_deps =
$(1): $(2) $(mkpage) $(macros)
	$(eval 1_trimmed := $(shell var="$(1)"; echo "$${var/ /}"))
	$(eval date := $(call last_modified_date, $(2)))
	m4 $(macros) $(2) | $(mkpage) $(mkpage_flags) >$(build)/$(1_trimmed)
endef

define template_post_with_deps =
$(1): $(2) $(3) $(mkpage) $(macros)
	$(eval 1_trimmed := $(shell var="$(1)"; echo "$${var/ /}"))
	$(eval date := $(call last_modified_date, $(2)))
	m4 $(macros) $(2) | $(mkpage) $(mkpage_flags) >$(build)/$(1_trimmed)
endef

#------------------------------------------------------------------------------
# Recipes
#------------------------------------------------------------------------------

# Look into the ./build and ./parts directories for files
vpath %.html $(build)
vpath %.html $(shell find ./parts -type d)

# Make the build directory before passing to the next recipes
build: $(shell [[ -d $(build) ]] || mkdir $(build))
build: $(pages_target) $(posts_target) $(stylesheet_target)\
       $(cert_target) $(key_target)

$(stylesheet_target): $(stylesheet)
	cp $(stylesheet) $(build)

$(cert_target): $(cert)
	cp $(cert) $(build)

$(key_target): $(key)
	cp $(key) $(build)

# Generates recipes with no dependencies
$(call gen_recipes_no_deps,$(pages),page)
$(call gen_recipes_no_deps,$(posts_without_deps),post)

# Generates recipes with dependencies
$(foreach post,$(posts_with_deps),\
	$(eval $(call template_post_with_deps,\
		$(notdir $(subst .post,,$(firstword $(subst :, ,$(post))))),\
		$(firstword $(subst :, ,$(post))),\
		$(wordlist 2,$(words $(subst :, ,$(post))),$(subst :, ,$(post)))\
	))\
)

# Start server
run-debug: server_flags += -v
run-debug run:
	@if [[ -d build ]] ; then \
		$(server) $(server_flags) ./build;\
	else \
		echo 'No build directory found. Please run: make or make build' ;\
	fi

clean:
	[[ -d build ]] && rm -r build
